/*
 * Created on Feb 11, 2005
 * Created by dfhuynh
 */
package edu.mit.simile.longwell.query.project;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;

import edu.mit.simile.longwell.Profile;

/**
 * @author dfhuynh
 */
public class PropertyProjector extends ProjectorBase {
	final protected Property 	m_property;
	final protected String		m_locale;
	final protected boolean		m_forward;
	
	protected Map m_objectToValue;
	
	/**
	 * @param profile
	 */
	public PropertyProjector(Profile profile, String parameter, String locale) {
		super(profile);
		
		if (parameter.startsWith("!")) {
			m_forward = false;
			parameter = parameter.substring(1);
		} else {
			m_forward = true;
		}
		
		int i = parameter.indexOf('@');
		if (i < 0) {
			m_property = m_profile.getModel().createProperty(parameter);
			m_locale = locale != null ? locale : "";
		} else {
			m_property = m_profile.getModel().createProperty(
				parameter.substring(0, i));
			m_locale = parameter.substring(i + 1);
		}
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjector#isEfficientForRootProjection()
	 */
	public boolean isEfficientForRootProjection() {
		return true;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjection#getUniqueness()
	 */
	public float getUniqueness() {
		return m_profile.getSchemaModel()
			.getStructuredProperty(m_property).getUniqueness();
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjector#getParameter()
	 */
	public String getParameter() {
		String s = m_forward ? "" : "!";
		
		s += m_property.getURI();
		if (m_locale != null && m_locale.length() > 0) {
			s += "@" + m_locale;
		}
		
		return s;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.IProjector#getLabel(java.lang.String)
	 */
	public String getLabel(String locale) {
		String label = m_profile.getSchemaModel().getLabel(m_property, locale, true);
		
		if (m_forward) {
			return label;
		} else {
			ResourceBundle resources = 
				ResourceBundle.getBundle(PropertyProjector.class.getName());
			
			return MessageFormat.format(
				resources.getString("BackwardPropertyLabelFormat"), 
				new Object[] { label });
		}
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.ProjectorBase#internalProject()
	 */
	protected IProjection internalProject() {
		return new PropertyProjection(
			m_profile, m_property, m_forward, m_locale, null) {
			
			/* (non-Javadoc)
			 * @see edu.mit.simile.longwell.query.project.ProjectionBase#internalGetObjectToValueMap()
			 */
			protected Map internalGetObjectToValueMap() {
				if (m_objectToValue == null) {
					m_objectToValue = new HashMap();
					fillObjectToValueMap(m_objectToValue);
				}
				return m_objectToValue;
			}

			@Override
			public String getProperty() {
				// TODO Auto-generated method stub
				return m_property.toString();
			}
		};
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.ProjectorBase#internalProject(java.util.Set)
	 */
	protected IProjection internalProject(Set objects) {
		return new PropertyProjection(
			m_profile, m_property, m_forward, m_locale, objects) {
			
			/* (non-Javadoc)
			 * @see edu.mit.simile.longwell.query.project.ProjectionBase#internalGetObjectToValueMap()
			 */
			protected Map internalGetObjectToValueMap() {
				if (m_objectToValue == null) {
					m_objectToValue = new HashMap();
					fillObjectToValueMap(m_objectToValue);
				}
				return m_objectToValue;
			}

			@Override
			public String getProperty() {
				// TODO Auto-generated method stub
				return m_property.toString();
			}
		};
	}

	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.project.ProjectorBase#onAfterChange(com.hp.hpl.jena.rdf.model.Model)
	 */
	protected void onAfterChange(Model model) {
		if (model.listStatements(null, m_property, (RDFNode) null).hasNext()) {
			m_resultCache.clear();
			if (m_objectToValue != null) {
				m_objectToValue.clear();
				m_objectToValue = null;
			}
		}
	}
}
